package com.uxsino.rule.nms.service;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.alibaba.fastjson.JSON;
import com.uxsino.rule.nms.strategy.dto.IndicatorTableDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.uxsino.commons.utils.StringUtils;
import com.uxsino.rule.nms.model.AnalysisResult;
import com.uxsino.rule.nms.strategy.dto.RuleDto;
import com.uxsino.rule.model.CompareType;
import com.uxsino.rule.model.ExistsCompareWay;
import com.uxsino.rule.model.HistoryCompareWay;
import com.uxsino.rule.model.StringCompareWay;
import com.uxsino.rule.model.NumberCompareWay;

/**
 * 组合策略子表达式语义解析---可以考虑运用解释器模式优化完善
 * 
 * @author MrFeng
 *
 */
public class CommandInterpreter {
    private static Logger logger = LoggerFactory.getLogger(CommandInterpreter.class);

    // 自定义告警模板占位识别正则
    //private static String CUSTOM_NOTICETEMPLATE_REGEXP = "(?<=\\$\\{)[(!\\/})a-zA-Z\\u4e00-\\u9fa5_0-9 ]*(?=\\})";

    /**
     * key : exp1,exp2,exp3...
     * value : RuleDto,RuleDto,RuleDto...
     * @param rule2
     * @param setting
     * @param indDto
     * @return
     */
    public static AnalysisResult commandAnalysis(JSONObject setting, RuleDto rule, IndicatorTableDto indDto) {
        StringBuffer simpleFormula = new StringBuffer();
        String formula = setting.getString("formula");
        String[] subExpressions = formula.split("[&|()]+");
        int i = 1;
        Map<String, RuleDto> subRuleMap = new HashMap<>();
        outter: for (String exp : subExpressions) {
            if (!StringUtils.isEmpty(exp.trim())) {
                try {
                    RuleDto subRule = expressionInterpret(exp, indDto);
                    for (Entry<String, RuleDto> entry : subRuleMap.entrySet()) {
                        if (subRule.equals(entry.getValue())) {
                            continue outter;
                        }
                    }
                    // 补全除去解析命令之外的信息
                    subRule.setNeComps(rule.getNeComps());
                    String subExpressionKey = "exp" + i++;
                    subRuleMap.put(subExpressionKey, subRule);
                    formula = formula.replace(exp, subExpressionKey);
                } catch (Exception e) {
                    logger.error("*******组合策略命令解析错误{}******", e);
                }
            }
        }
        simpleFormula.append(formula);
        AnalysisResult result = new AnalysisResult();
        result.setSimpleFormula(simpleFormula.toString());
        result.setSubRuleMap(subRuleMap);
        return result;
    }

    /**
     * range ${属性名} begin=? end=?
     * sum compareWay value=?
     * string ${属性名} compareWay value=?
     * exists ${属性名} compareWay value=?
     * history ${属性名} compareWay ini=? tar=?
     * @param expression
     * @param indicator
     * @return
     */
    private static RuleDto expressionInterpret(String expression, IndicatorTableDto indDto) {
        RuleDto rule = new RuleDto();
        String compareType = expression.trim().split("[ ]+", 2)[0];
        String rests = expression.trim().split("[ ]+", 2)[1];
        rule.setCompareType(CompareType.valueOf(compareType));
        JSONArray settings = new JSONArray();
        JSONObject setting = new JSONObject();
        try {
            if (CompareType.sum.equals(rule.getCompareType())) {// sum
                String compareWay = rests.split("[ ]+", 2)[0];
                rests = rests.split("[ ]+", 2)[1];
                NumberCompareWay cw = NumberCompareWay.valueOf(compareWay);
                setting.put("compareWay", cw.name());
                if (rests.startsWith("value=")) {
                    setting.put("value", rests.substring(6));
                }
            } else {// range,history,exists,string
                    // **********************************
                /*Pattern pattern = Pattern.compile(CUSTOM_NOTICETEMPLATE_REGEXP);
                Matcher m = pattern.matcher(rests.split("[ ]+",2)[0]);
                m.find();
                String fieldText = m.group();*/
                //String fieldStr = rests.split("}[ ]+", 2)[0];
                String fieldText = StringUtils.isEmpty(rests) ? ""
                        : rests.substring(rests.indexOf("${")+2, rests.lastIndexOf("}"));
                rests = rests.split("}[ ]+", 2)[1];
                JSONArray fieldArray = indDto.getFields();
                boolean fieldInterpretSuccess = false;
                for (Object field : fieldArray) {
                    JSONObject fielJson = JSON.parseObject(field.toString());
                    if (fielJson != null && fieldText.equals(fielJson.getString("label"))) {
                        rule.setFieldName(fielJson.getString("name"));
                        rule.setFieldText(fieldText);
                        fieldInterpretSuccess = true;
                        break;
                    }
                }
                // **********************************
                if (fieldInterpretSuccess) {
                    if (CompareType.range.equals(rule.getCompareType())) {// range
                        String begin = "";
                        String end = "";
                        if (rests.startsWith("begin=") && rests.contains("end=")) {
                             begin = rests.substring(6, rests.lastIndexOf("end="));
                             end = rests.substring(rests.lastIndexOf("end=") + 4);
                            setting.put("begin", begin.trim());
                            setting.put("end", end.trim());
                        }else if(rests.startsWith("begin=") && !rests.contains("end=")) {
                            begin = rests.substring(6);
                           setting.put("begin", begin.trim());
                           setting.put("end", end.trim());
                        } else if(!rests.contains("begin=") && rests.startsWith("end=")){
                            end = rests.substring(4);
                           setting.put("begin", begin.trim());
                           setting.put("end", end.trim());
                        }else {
                            throw new Exception("range表达式解析错误");
                        }
                    } else {// history,exists,string
                        String compareWay = rests.split("[ ]+", 2)[0];
                        rests = rests.split("[ ]+", 2)[1];
                        switch (rule.getCompareType()) {
                        case string:
                            StringCompareWay stringCompareWay = stringCompareMapping(compareWay);
                            if (stringCompareWay == null) {
                                return null;
                            }
                            setting.put("compareWay", stringCompareMapping(compareWay).name());
                            break;

                        case exists:
                            setting.put("compareWay", ExistsCompareWay.valueOf(compareWay).name());
                            break;

                        case history:
                            setting.put("compareWay", HistoryCompareWay.valueOf(compareWay).name());
                            break;

                        default:
                            break;
                        }
                        if (CompareType.history.equals(rule.getCompareType())) {
                            if (rests.startsWith("ini=") && rests.contains("tar=")) {
                                String inital_value = rests.substring(6, rests.lastIndexOf("tar="));
                                String target_value = rests.substring(rests.lastIndexOf("tar=") + 4);
                                setting.put("inital_value", inital_value);
                                setting.put("target_value", target_value);
                            } else {
                                throw new Exception("history表达式解析错误");
                            }
                        } else {
                            if (rests.startsWith("value=")) {
                                setting.put("value", rests.substring(6));
                            } else {
                                throw new Exception("range表达式解析错误");
                            }
                        }
                    }
                }

            }
            settings.add(setting);
            rule.setSettings(settings.toJSONString());
        } catch (Exception e) {
            logger.error("组合策略表达式解析错误！{}", e);
            rule = null;
        }
        return rule;
    }

    public static StringCompareWay stringCompareMapping(String compareWay) {
        switch (compareWay) {
        case "contains":
            return StringCompareWay.CONTAINS;

        case "notcontains":
            return StringCompareWay.NOT_CONTAINS;

        case "prefix":
            return StringCompareWay.START_WITH;

        case "suffix":
            return StringCompareWay.END_WITH;

        case "equals":
            return StringCompareWay.EQUALS;

        case "notequals":
            return StringCompareWay.NOT_EQUALS;

        default:
            return null;
        }
    }

}
